import { Dispatch } from '../../react/src/currentDispatcher';
import { Dispatcher } from '../../react/src/currentDispatcher';
import internals from 'shared/internals';
import { Action, ReactContext, Thenable, Usable } from 'shared/ReactTypes';
import { FiberNode } from './fiber';
import { Flags, PassiveEffect } from './fiberFlags';
import {
	Lane,
	NoLane,
	NoLanes,
	mergeLanes,
	removeLanes,
	requestUpdateLane
} from './fiberLanes';
import { HookHasEffect, Passive } from './hookEffectTags';
import {
	basicStateReducer,
	createUpdate,
	createUpdateQueue,
	enqueueUpdate,
	processUpdateQueue,
	Update,
	UpdateQueue
} from './updateQueue';
import { scheduleUpdateOnFiber } from './workLoop';
import { trackUsedThenable } from './thenable';
import { REACT_CONTEXT_TYPE } from 'shared/ReactSymbols';
import { markWipReceivedUpdate } from './beginWork';
import { readContext as readContextOrigin } from './fiberContext';

//  三大阶段 调度阶段  render 阶段 commit阶段
let currentlyRenderingFiber: FiberNode | null = null; // 表示 当前正在render阶段的 fiber节点 里面存放着 hooks链表

let workInProgressHook: Hook | null = null; // 函数组件执行的时候 里面有hooks 函数 workInProgressHook 表示当前正在处理的 hook
// useState 等hook执行的时候 workInProgressHook 为null时表示 是函数组件里面 的第一hooks函数

let currentHook: Hook | null = null; //currentHook记录着 函数组件更新阶段处理完的 hooks
let renderLane: Lane = NoLane;

const { currentDispatcher, currentBatchConfig } = internals;

function readContext<Value>(context: ReactContext<Value>): Value {
	const consumer = currentlyRenderingFiber as FiberNode;
	return readContextOrigin(consumer, context);
}

// 满足所有hooks函数的使用
interface Hook {
	memoizedState: any; // 不用 hooks 保存的 数据类型不一样 useState 保存的是 state  Effect类型的hook 保存的是 Effect
	// useState memoizedState 保存的是 state
	// useEffect memoizedState 保存的是 update
	updateQueue: unknown; // 因为 hooks 可以触发更新 所以需要一个 updateQueue 字段  存update更新的 结构  后面去消费这个 updateQueue 触发更新
	// 后面 dispatch 的时候 把新的state  通过 创建update更新 设置到updateQueue里面去
	// 然后 后面 获取新state状态的时候去消费这个更新 就能得到最新的 state状态
	next: Hook | null; // 指向下个hook

	// 有这个这样的问题：当低优先级的更新消费了 update的时候 就会将 hook.updateQueue.pending 设置为null 就是将update销毁
	// 但有个问题就是 低优先级的任务被高优先级任务打断了  hook.updateQueue.pending  被销毁了后续 低优先级任务执行的时候怎么去 重新获取 对应的update
	// 解决：
	// 保存update的问题
	// 考虑将update保存在current hook中。只要不进入commit阶段，current与wip不会互换，所以保存在current hook中，即使多次执行render阶段，只要不进入commit阶段，都能从current hook中恢复数据。
	baseState: any; // 开始为memoizedState 或者 第一次遇到没有匹配上的update 的时候上一次匹配到update的 计算结果 后面再遇到没有匹配上的就不会变了？？？
	baseQueue: Update<any> | null; // 包含第一次跳过的update 之后的 所有update 链表 没变被跳过的update 的lane被重置为了null
}

export interface Effect {
	tag: Flags; //effect 的 类型 代表什么类型的副作用 并且还能表示该副作用函数 是否需要执行
	create: EffectCallback | void; //  创建时的副作用
	destroy: EffectCallback | void; // 组件销毁时的副作用
	deps: HookDeps; // 依赖
	next: Effect | null; // 执行下一个 effect 类型的副作用 这里的 next 和 hook.next 是不一样的 hook.next 是指向下一个hook 这里的 next 是指向下一个effect
	// 为什么 effect 是链表结构呢 因为  为了 执行 副作用的 时候 方便查找下一个 effect  看下一个 effect 是否需要执行
}

// 当前 fiber 带有带有 副作用的 UpdateQueue 他比 UpdateQueue 新增了 两个字段
// lastEffect： 执行 effect 环状链表的 最后一个 effect   lastEffect.next 指向第一个effect
export interface FCUpdateQueue<State> extends UpdateQueue<State> {
	lastEffect: Effect | null;
	lastRenderedState: State;
}

type EffectCallback = () => void;
export type HookDeps = any[] | null;

export function renderWithHooks(
	wip: FiberNode,
	Component: FiberNode['type'],
	lane: Lane
) {
	// 执行 函数组件之前 将 currentlyRenderingFiber = wip;
	// 赋值操作
	currentlyRenderingFiber = wip;
	// 重置 hooks链表  因为重新执行了 需要创建新的链表  如果是 更新的话 就去 wip.alternate 上去取老的链表
	wip.memoizedState = null;
	// 重置 effect链表
	wip.updateQueue = null; //和memoizedState 同理
	renderLane = lane;

	const current = wip.alternate;

	// reconciler 根据不同阶段 给 hooks 共享数据 里面的currentDispatcher.current 设置不同的值
	// 大概原理 和 duyi写的 react 差不多 就是 首次渲染 那就 创建一个hook
	//  更新的话 就去 fiber 上取 之前的老Fiber
	if (current !== null) {
		// update
		currentDispatcher.current = HooksDispatcherOnUpdate;
	} else {
		// mount
		currentDispatcher.current = HooksDispatcherOnMount;
	}

	// 这样过后  函数里面 执行 具体 useState 这样的hook时  就是 根据不同阶段 不同的函数了

	const props = wip.pendingProps;
	// FC render
	// 函数组件执行 里面如果使用了 hook是就会创建 hooks链表
	const children = Component(props);

	// 重置操作
	currentlyRenderingFiber = null;
	workInProgressHook = null;
	currentHook = null;
	renderLane = NoLane;
	return children;
}

//  fiber mount 阶段 dispatcher 里面的具体实现
// 函数里面 执行 具体 useState 这样的hook时  就是 根据 首次渲染 和 更新阶段 对应不同的函数
const HooksDispatcherOnMount: Dispatcher = {
	useState: mountState,
	useEffect: mountEffect,
	useTransition: mountTransition,
	useRef: mountRef,
	useContext: readContext,
	use,
	useMemo: mountMemo,
	useCallback: mountCallback
};

//  fiber 更新 阶段 dispatcher 里面的具体实现
// 函数组件重新渲染了 里面的 hooks 重新执行 就会执行这里面对应的 hooks函数
const HooksDispatcherOnUpdate: Dispatcher = {
	useState: updateState,
	useEffect: updateEffect,
	useTransition: updateTransition,
	useRef: updateRef,
	useContext: readContext,
	use,
	useMemo: updateMemo,
	useCallback: updateCallback
};

// currentDispatcher.current 在mount 和 update 阶段分别执行不同的 Dispatcher
// 还有 当 useEffect(fn,[]) 的 fn执行的时候  会将 currentDispatcher.current = {useState :(){new Error('不能在hooks里套hooks执行，不能在函数组件上下文之外的上下文中执行hooks')}}
// 就是 hooks 不能在 函数组件外的上下文中执行
// useEffect(()=>{const [a,setA] = useState(0);useEffect(()=>{})},[]) 这样嵌套使用时不行的

function mountEffect(create: EffectCallback | void, deps: HookDeps | void) {
	const hook = mountWorkInProgressHook();
	const nextDeps = deps === undefined ? null : deps;
	(currentlyRenderingFiber as FiberNode).flags |= PassiveEffect;

	// 创建 一个 effect 并将 该 effect 插入  effect 环状链表中
	// 该effect 环状链表 保存 在 fiber.updateQueue.lastEffect 中 lastEffect 表示 effect 环状链表的最后一个effect
	// fiber.updateQueue.lastEffect.next 指向 effect 环状链表的第一个effect
	hook.memoizedState = pushEffect(
		Passive | HookHasEffect, // 表示该effect 是 useEffect 且需要执行回调函数
		create,
		undefined,
		nextDeps
	);
}

function updateEffect(create: EffectCallback | void, deps: HookDeps | void) {
	const hook = updateWorkInProgressHook();
	const nextDeps = deps === undefined ? null : deps;
	let destroy: EffectCallback | void;

	if (currentHook !== null) {
		const prevEffect = currentHook.memoizedState as Effect;
		destroy = prevEffect.destroy;

		if (nextDeps !== null) {
			// 浅比较依赖
			const prevDeps = prevEffect.deps;
			if (areHookInputsEqual(nextDeps, prevDeps)) {
				// 顺序遍历数组的 同一位置 浅比较 相等则 不标记这个effect 需要 执行副作用
				hook.memoizedState = pushEffect(Passive, create, destroy, nextDeps);
				return;
			}
		}

		// 浅比较 不相等 或者 // useEffect 第二个参数为空的情况下 就每次都要重新执行 副作用
		(currentlyRenderingFiber as FiberNode).flags |= PassiveEffect;

		hook.memoizedState = pushEffect(
			Passive | HookHasEffect,
			create,
			destroy,
			nextDeps
		);
	}
}

function areHookInputsEqual(nextDeps: HookDeps, prevDeps: HookDeps) {
	if (prevDeps === null || nextDeps === null) {
		return false;
	}
	for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
		if (Object.is(prevDeps[i], nextDeps[i])) {
			continue;
		}
		return false;
	}
	return true;
}

function pushEffect(
	hookFlags: Flags,
	create: EffectCallback | void,
	destroy: EffectCallback | void,
	deps: HookDeps
): Effect {
	const effect: Effect = {
		tag: hookFlags,
		create,
		destroy,
		deps,
		next: null
	};
	const fiber = currentlyRenderingFiber as FiberNode;
	const updateQueue = fiber.updateQueue as FCUpdateQueue<any>;
	if (updateQueue === null) {
		// 当前 fiber 不存在  updateQueue 新建一个 updateQueue
		const updateQueue = createFCUpdateQueue();
		fiber.updateQueue = updateQueue;
		effect.next = effect; // 环状链表  因为 目前只有一个 effect 所以 自己的next 指向自己
		updateQueue.lastEffect = effect;
	} else {
		// 当前fiber 存在 updateQueue
		// 插入effect
		const lastEffect = updateQueue.lastEffect;
		if (lastEffect === null) {
			// 判断 lastEffect 存不存在 不存在 重复 updateQueue 存存在的操作
			// 因为 可能 函数组件里面第一个hook是useState  已经创建了updateQueue 所以 updateQueue 不为null 但是 lastEffect 为null
			effect.next = effect;
			updateQueue.lastEffect = effect;
		} else {
			// lastEffect 此时指向的是effect4
			// effect1 effect2 effect3   effect4  effect4.next = effect1
			//当前插入 effect5
			// 需要做的就是 先 将 取到 effect1
			// 然后将 effect4.next = effect5
			// 然后 effect5.next = effect1
			const firstEffect = lastEffect.next; // 到 effect1 取得第一个effect
			lastEffect.next = effect; // 将之前的最后一个effect 指向 新插入的effect
			effect.next = firstEffect; // 将新插入的effect.next 指向 第一个effect
			updateQueue.lastEffect = effect; // 将lastEffect 指向 新插入的effect 也就是 最后一个插入的
		}
	}
	return effect;
}

function createFCUpdateQueue<State>() {
	const updateQueue = createUpdateQueue<State>() as FCUpdateQueue<State>;
	updateQueue.lastEffect = null;
	return updateQueue;
}

function updateState<State>(): [State, Dispatch<State>] {
	// 找到当前useState对应的hook数据
	const hook = updateWorkInProgressHook();

	// 计算新state的逻辑

	// 依据 update 计算 update保存在hook的 updateQueue里
	const queue = hook.updateQueue as FCUpdateQueue<State>;
	const baseState = hook.baseState; // 当前hook对应是 baseState

	const pending = queue.shared.pending; // 当前 update链表
	const current = currentHook as Hook; // 当前hook

	let baseQueue = current.baseQueue; // 当前存在 hook 上的baseQueue

	if (pending !== null) {
		// pending baseQueue update保存在current中
		if (baseQueue !== null) {
			// 如果 baseQueue 存在 则将 baseQueue 和 pending 合并 合并后 baseQueue 在前面 pending靠后面
			// baseQueue b2 -> b0 -> b1 -> b2
			// pendingQueue p2 -> p0 -> p1 -> p2
			// b0
			const baseFirst = baseQueue.next; // baseQueue的第一个 update
			// p0
			const pendingFirst = pending.next; // pending的第一个update
			// b2 -> p0
			baseQueue.next = pendingFirst; // 将 baseQueue.next 指向 pending的第一个update
			//  baseQueue：1 2 3 4      pending ： 7 8 9 10
			// 本来baseQueue指向4的 baseQueue.next 指向1的
			// 本来pending指向10的 pending.next 指向7的
			// 就是将 4.next 执行 7
			// p2 -> b0
			// 然后将10.next 指向1
			pending.next = baseFirst;
			// p2 -> b0 -> b1 -> b2 -> p0 -> p1 -> p2
		}
		baseQueue = pending; // 将 baseQueue 赋值为 pending 就是指向10 表示 合并的链表的 最后一个update

		current.baseQueue = pending; // 合并后保存在current中
		queue.shared.pending = null; // 清空 pending 不然下次更新会重复
	}

	if (baseQueue !== null) {
		const prevState = hook.memoizedState; // prevState 表示更新之前的state
		// 消费这个 update 传入老的state 然后 根据 update 计算出 新的 state
		// update 就是 baseQueue 可能是一个 值 有可能是一个 函数 (preState)=>{}
		// setState(1) setState((preState)=>1+preState)
		// 这个 update 是 dispatch 的时候 注入到hook里面的updateQueue里面的
		const {
			memoizedState,
			baseQueue: newBaseQueue,
			baseState: newBaseState
		} = processUpdateQueue(baseState, baseQueue, renderLane, (update) => {
			const skippedLane = update.lane;
			const fiber = currentlyRenderingFiber as FiberNode;
			// NoLanes
			fiber.lanes = mergeLanes(fiber.lanes, skippedLane);
		});

		// NaN === NaN // false
		// Object.is true

		// +0 === -0 // true
		// Object.is false
		if (!Object.is(prevState, memoizedState)) {
			markWipReceivedUpdate();
		}

		// 计算后 在hook上保存对应的值
		hook.memoizedState = memoizedState;
		hook.baseState = newBaseState;
		hook.baseQueue = newBaseQueue;

		queue.lastRenderedState = memoizedState;
	}

	// queue.dispatch 就是 初次渲染的时候 放到hook的 UpdateQueue 里面的
	// 这样了就不用 重新返回dispatch了 保持 dispatch 函数引用不变
	return [hook.memoizedState, queue.dispatch as Dispatch<State>];
}

// hooks 更新阶段  重新执行 有两种方式
// 交互阶段触发的更新
// <div onClick={() => update(1)}></div>
// render阶段触发的更新（TODO） 情况二
// function App() {
//   const [num, update] = useState(0);
//   // 触发更新
//   update(100);
//   return <div>{num}</div>;
// }

function updateWorkInProgressHook(): Hook {
	// TODO render阶段触发的更新 这里还需要处理一个逻辑就是情况二

	let nextCurrentHook: Hook | null; // 表示 当前useHooks函数 的对应的 hook对象

	// currentHook  记录着 函数组件更新阶段处理完的 hooks
	if (currentHook === null) {
		// 这是这个FC update时的第一个hook
		// 看当前现实区的Fiber
		const currentFiber = (currentlyRenderingFiber as FiberNode).alternate;
		if (currentFiber !== null) {
			nextCurrentHook = currentFiber.memoizedState;
		} else {
			// mount 这里是 边界情况 不用管
			// 正常是走不到这里来的 因为 更新阶段current 肯定有值
			nextCurrentHook = null;
		}
	} else {
		// 这个FC update时 后续的hook
		nextCurrentHook = currentHook.next;
	}

	if (nextCurrentHook === null) {
		// 因为到 执行 u4的时候 currentHook 此时是等于老的u3的 然后nextCurrentHook  = u3.next 此时 u3.next 为null 所以就会报错
		// u 表示 useState 等这种hooks函数
		// 首次渲染时事三个
		//  mount/update u1 u2 u3
		// 后面变成了 4个 就是将hooks函数放 if 判断里面了
		// update       u1 u2 u3 u4
		throw new Error(
			`组件 ${currentlyRenderingFiber?.type.name} 本次执行时的Hook比上次执行时多`
		);
	}

	currentHook = nextCurrentHook as Hook;
	// 这里表示 复用之前的 hooks
	const newHook: Hook = {
		memoizedState: currentHook.memoizedState,
		updateQueue: currentHook.updateQueue,
		next: null,
		baseQueue: currentHook.baseQueue,
		baseState: currentHook.baseState
	};
	// 走到这就和 初次渲染一样了
	// 因为这里 创造了 一个全新的newHook 所以需要将其链起来
	if (workInProgressHook === null) {
		// mount时 第一个hook
		if (currentlyRenderingFiber === null) {
			throw new Error('请在函数组件内调用hook');
		} else {
			workInProgressHook = newHook;
			currentlyRenderingFiber.memoizedState = workInProgressHook;
		}
	} else {
		// mount时 后续的hook
		workInProgressHook.next = newHook;
		workInProgressHook = newHook;
	}
	return workInProgressHook;
}

function mountState<State>(
	initialState: (() => State) | State
): [State, Dispatch<State>] {
	// 找到当前useState对应的hook数据
	const hook = mountWorkInProgressHook();
	let memoizedState;

	// 如果 state 传入的是一个 函数
	if (initialState instanceof Function) {
		// 那就执行函数 获取 state
		memoizedState = initialState();
	} else {
		memoizedState = initialState;
	}

	// 因为 useState 是可以 触发更新的 所以需要 创建一个可消费的更新
	// 后面更新的时候 去消费这个更新
	const queue = createFCUpdateQueue<State>();

	hook.updateQueue = queue;

	hook.memoizedState = memoizedState; // 更新 hook里面的 memoizedState
	hook.baseState = memoizedState;

	// useState 首次执行的时候 创建一个 queue 用 存放 update
	// update 会在dispatch 执行的时候 创建 然后 将 update 里面的 action 赋值为 dispatch  传入的 函数 或者state
	// 当 后面 函数组件因为 触发了dispatch   重新执行 useState 再执行的时候 会从 currentlyRenderingFiber 中拿到 这个queue
	// 从而拿到queue 里面保存到  update  然后再消费这个 queue 就能 获取到最新的状态

	// dispatch 函数里面 通过bind函数绑定了 该函数组件对应的Fiber 和 消费更新
	// 为什么要bind  保存currentlyRenderingFiber  因为dispatch 是可以 脱离函数组件去使用的
	// 比如 const [a,setA] = useState(0)
	// window.setA =setA;
	// 在全局环境 setA() 也可以触发更新
	// @ts-ignore
	const dispatch = dispatchSetState.bind(null, currentlyRenderingFiber, queue);

	// 为了 兼容 hooks queue 中增加 dispatch 属性

	//  把dispatch 函数放到hook.updateQueue.dispatch 中 这样 后面更新阶段返回dispatch 就是 这里定义的dispatch 函数
	// 这样了就不用 重新返回dispatch了 保持 dispatch 函数引用不变
	queue.dispatch = dispatch;

	queue.lastRenderedState = memoizedState;

	return [memoizedState, dispatch];
}

// const [isPending, startTransition] = React.useTransition();
// useTransition 返回一个函数
// 用该函数包裹一个回调函数
// 内部会进行3次触发更新 第二次和第三次更新是可以被 其他更高优先级任务 插入打断的
// 1. setIsPending(true) 将isPending 值设置为true 触发一次更新
// 2.改变 优先级   改变成 TransitionLane 异步宏任务切片更新
// 3.callBack() 执行 里面如果有 set操作 就会再触发一次更新
// 4. setIsPending(false) 将isPending 值设置为false 触发一次更新
// callBack()  setIsPending(false) 会在同一个优先级中 执行 因为他们的优先级是一样的
// 5. 还完 调度器上下文 优先级
function startTransition(setPending: Dispatch<boolean>, callback: () => void) {
	setPending(true);
	const prevTransition = currentBatchConfig.transition;
	currentBatchConfig.transition = 1; // 这边表示改变了优先级
	// 然后 requestUpdateLane 方法去获取优先级的时候 就会返回 TransitionLane
	// 为1 这里表示不去 调度器内部优先级去获取 而是 应该用 TransitionLane
	// TransitionLane 对应调度器内 最低的优先级

	callback();
	setPending(false);

	currentBatchConfig.transition = prevTransition; // 还原优先级
}

function mountTransition(): [boolean, (callback: () => void) => void] {
	const [isPending, setPending] = mountState(false); // hook 里面套 hook
	const hook = mountWorkInProgressHook();
	const start = startTransition.bind(null, setPending); // 定义包装callBack的 startTransition 接收 setPending 因为里面会 设置isPending 的值
	hook.memoizedState = start;
	return [isPending, start];
}

function updateTransition(): [boolean, (callback: () => void) => void] {
	const [isPending] = updateState(); // 直接利用updateState 拿到 对应的hook 再取值
	const hook = updateWorkInProgressHook();
	const start = hook.memoizedState;
	return [isPending as boolean, start];
}

function mountRef<T>(initialValue: T): { current: T } {
	const hook = mountWorkInProgressHook();
	const ref = { current: initialValue };
	hook.memoizedState = ref;
	return ref;
}

function updateRef<T>(initialValue: T): { current: T } {
	const hook = updateWorkInProgressHook();
	return hook.memoizedState;
}
// dispatchSetState 可能有 多种触发更新的 场景
// 比如在在click 产生的更新 还有就是在 useEffect 函数中 产生的更新
function dispatchSetState<State>(
	fiber: FiberNode,
	updateQueue: FCUpdateQueue<State>,
	action: Action<State>
) {
	// 不同场景 返回不用优先级
	const lane = requestUpdateLane();

	// updateCount((count) => count + 1);
	// updateCount((count) => count + 2);
	// updateCount((count) => count + 2);
	// 这里可能是这种情况 连续3次触发更新 那 不能简单覆盖 需要将update  设置为链表的结构
	// 将第二次更新的 update 插入前一个update 的next属性上
	// 要触发更新的话 先创建一个 update 存入 要更新的值
	const update = createUpdate(action, lane);

	// eager策略
	const current = fiber.alternate;
	if (
		fiber.lanes === NoLanes &&
		(current === null || current.lanes === NoLanes)
	) {
		// 当前产生的update是这个fiber的第一个update
		// 1. 更新前的状态 2.计算状态的方法
		const currentState = updateQueue.lastRenderedState;
		const eagerState = basicStateReducer(currentState, action);
		update.hasEagerState = true;
		update.eagerState = eagerState;

		if (Object.is(currentState, eagerState)) {
			enqueueUpdate(updateQueue, update, fiber, NoLane);
			// 命中eagerState
			if (true) {
				console.warn('命中eagerState', fiber);
			}
			return;
		}
	}

	// 将 更新 插入 到 hook的 updateQueue 中 后面 函数组件重新渲染了 就去 updateQueue中取 这个最新的 update 也就是 消费这个更新
	// 绕一大圈 原理就是 在fiber节点上 保存 更新后的数据
	enqueueUpdate(updateQueue, update, fiber, lane);

	// 拿到当前Fiber 触发更新
	// 通过当前Fiber协调更新
	// 内部会 一直向上找父节点 然后从 root 开始更新
	scheduleUpdateOnFiber(fiber, lane);
}

function mountWorkInProgressHook(): Hook {
	const hook: Hook = {
		memoizedState: null,
		updateQueue: null,
		next: null,
		baseQueue: null,
		baseState: null
	};
	if (workInProgressHook === null) {
		// mount时 第一个hook
		if (currentlyRenderingFiber === null) {
			// 因为 在普通函数中使用 hooks 不是在函数组件 中的话
			// 是没有做初始化准备的 currentlyRenderingFiber 肯定为null
			throw new Error('请在函数组件内调用hook');
		} else {
			workInProgressHook = hook;
			currentlyRenderingFiber.memoizedState = workInProgressHook;
		}
	} else {
		// mount时 后续的hook
		workInProgressHook.next = hook; // 链表 链上
		workInProgressHook = hook; // 设置为当前hook
	}
	return workInProgressHook;
}

function use<T>(usable: Usable<T>): T {
	if (usable !== null && typeof usable === 'object') {
		if (typeof (usable as Thenable<T>).then === 'function') {
			const thenable = usable as Thenable<T>;
			return trackUsedThenable(thenable);
		} else if ((usable as ReactContext<T>).$$typeof === REACT_CONTEXT_TYPE) {
			const context = usable as ReactContext<T>;
			return readContext(context);
		}
	}
	throw new Error('不支持的use参数 ' + usable);
}

export function resetHooksOnUnwind(wip: FiberNode) {
	currentlyRenderingFiber = null;
	currentHook = null;
	workInProgressHook = null;
}

export function bailoutHook(wip: FiberNode, renderLane: Lane) {
	const current = wip.alternate as FiberNode;
	wip.updateQueue = current.updateQueue;
	wip.flags &= ~PassiveEffect;

	current.lanes = removeLanes(current.lanes, renderLane);
}

function mountCallback<T>(callback: T, deps: HookDeps | undefined) {
	const hook = mountWorkInProgressHook();
	const nextDeps = deps === undefined ? null : deps;
	hook.memoizedState = [callback, nextDeps];
	return callback;
}

function updateCallback<T>(callback: T, deps: HookDeps | undefined) {
	const hook = updateWorkInProgressHook();
	const nextDeps = deps === undefined ? null : deps;
	const prevState = hook.memoizedState;

	if (nextDeps !== null) {
		const prevDeps = prevState[1];
		if (areHookInputsEqual(nextDeps, prevDeps)) {
			return prevState[0];
		}
	}
	hook.memoizedState = [callback, nextDeps];
	return callback;
}

function mountMemo<T>(nextCreate: () => T, deps: HookDeps | undefined) {
	const hook = mountWorkInProgressHook();
	const nextDeps = deps === undefined ? null : deps;
	const nextValue = nextCreate();
	hook.memoizedState = [nextValue, nextDeps];
	return nextValue;
}

function updateMemo<T>(nextCreate: () => T, deps: HookDeps | undefined) {
	const hook = updateWorkInProgressHook();
	const nextDeps = deps === undefined ? null : deps;
	const prevState = hook.memoizedState;

	if (nextDeps !== null) {
		const prevDeps = prevState[1];
		if (areHookInputsEqual(nextDeps, prevDeps)) {
			return prevState[0];
		}
	}
	const nextValue = nextCreate();
	hook.memoizedState = [nextValue, nextDeps];
	return nextValue;
}
